﻿/********************************************************************************
** @ Date:2024/12/06
** @ Author: AoZhiQiang
** @ Description: 语音播报类
** @ Version:1.0.0
** @ Fun:
********************************************************************************/
#ifndef CSpeechAlert_H
#define CSpeechAlert_H

#include "QThreadBase.h"

#include <QLocale>
#include <QVoice>
#include <QVector>
#include <QTextToSpeech>
#include <QMutex>
#include <QQueue>
#include <QUuid>
#include <QEventLoop>
#include <QTimer>
#include <QTimerEvent>
#include <QElapsedTimer>

class CSpeechAlert : public QThreadBase
{
	Q_OBJECT

public:
	//播报次数类型
	enum EFrequency
	{
		enFixed,                  //固定值 1次、2次、3次...
		enLoop                    //循环
	};

	//播报配置
	struct SSpeechSet
	{
		QString sId;              //自动生成的Id
		QString sContent;         //播报内容
		int nFixedNum;            //固定播放次数
		EFrequency enType;        //播报次数类型
		int nSpeechTimeLimit;     //播报限制时间(单位: ms)
		SSpeechSet()
		{
			sId = QUuid::createUuid().toString().remove(QRegExp("[{}]"));;
			sContent = QString::fromLocal8Bit("测试语音");
			nFixedNum = 1;
			enType = enFixed;
			nSpeechTimeLimit = 0;
		}
	};

public:
	CSpeechAlert();
	~CSpeechAlert();

	/**
	* @brief getInstance 获取单例
	* @param
	*/
	static CSpeechAlert* getInstance();

	/**
	* @brief getAvailableEngines 获取可用引擎名称
	* @param
	*/
	QStringList getAvailableEngines();

	/**
	* @brief getAvailableLocales 获取可用语言
	* @param
	*/
	QStringList getAvailableLocales();

	/**
	* @brief getAvailableVoice 获取可用声音
	* @param
	*/
	QStringList getAvailableVoice();

	/**
	* @brief getEngine 设置引擎
	* @param sEngineName 引擎名称
	*/
	bool setEngine(const QString &sEngineName);

	/**
	* @brief setLocale 设置语言
	* @param sLocaleName 语言名称
	*/
	bool setLocale(const QString &sLocaleName);

	/**
	* @brief setVoice 设置声音
	* @param sVoiceName 声音名称
	*/
	bool setVoice(const QString &sVoiceName);

	/**
	* @brief setRate 设置语速
	* @param nRate 语速    1.0为默认语速，小于1.0会使语音播放变慢，大于1.0则会使播放变快。
	*/
	void setRate(float fRate);

	/**
	* @brief setPitch 设置音调
	* @param nPitch 音调   1.0为默认音调，小于1.0会使声音变低，大于1.0会使声音变高。
	*/
	void setPitch(float fPitch);

	/**
	* @brief setVolume 设置音量
	* @param nVolume 音量   0.0 - 1.0
	*/
	void setVolume(float fVolume);

	/**
	* @brief setPause 暂停
	* @param bPause 是否暂停
	*/
	void setPause(bool bPause);

	/**
	* @brief speech 播报 添加到队列 按顺序播报  返回值为播报唯一标识
	* @param stSpeech 播报配置
	*/
	QString speech(SSpeechSet stSpeech);

	/**
	* @brief speechNow 立刻播报   返回值为播报唯一标识
	* @param stSpeech 播报配置
    */
	QString speechNow(SSpeechSet stSpeech);

	/**
	* @brief removeByContent 通过内容标识移除播报
	* @param sContent 内容
	*/
	void removeByContent(const QString &sContent);

	/**
	* @brief removeById 通过生成的Id标识移除播报
	* @param sId 插入时生成的Id
	*/
	void removeById(const QString &sId);

	/**
	* @brief removeAll 清空所有队列
	* @param 
	*/
	void removeAll();

	/**
	* @brief openLog 开启日志
	* @param
	*/
	void openLog(bool bOpen);

protected:
	//定时器 监测是否按时限中断播报
	void timerEvent(QTimerEvent *event) override;

private:
	/**
	* @brief initData 初始化数据
	* @param
	*/
	void initData();

	/**
	* @brief loadEngine 加载引擎
	* @param
	*/
	void loadEngines();

	/**
	* @brief loadLocales 加载语言
	* @param
	*/
	void loadLocales();

	/**
	* @brief loadVoice 加载声音
	* @param
	*/
	void loadVoice();

	/**
	* @brief handleSpeech 处理播报
	* @param
	*/
	void handleSpeech();

	/**
	* @brief writeToFile 将日志写入到文件
	* @param
	*/
	void writeToFile(const QString &sLog);

protected slots:
	/**
	* @brief slotWorkProc 工作线程
	* @param
	*/
	void slotWorkProc() override;

private slots:
	/**
	* @brief slotStateChanged 状态改变
	* @param
	*/
	void slotStateChanged(QTextToSpeech::State state);

	/**
	* @brief slotSpeechFinished 播报结束
	* @param
	*/
	void slotSpeechFinished();

signals:
	/**
	* @brief sigSpeechFinished 播报结束
	* @param
	*/
	void sigSpeechFinished();

public:
	static CSpeechAlert* m_pInstance;                         //单例
	static QMutex m_locker;                                   //锁

private:
	//垃圾回收类  释放单列指针
	class CSpeechAlertTrush
	{
	public:
		~CSpeechAlertTrush()
		{
			if (CSpeechAlert::m_pInstance != nullptr)
			{
				delete  CSpeechAlert::m_pInstance;
				CSpeechAlert::m_pInstance = nullptr;
			}
		}
	};

	static CSpeechAlertTrush uTrush;   //定义静态变量  系统结束自动释放该类  调用析构方法从而释放指针

private:
	/*语音播放相关*/
	QTextToSpeech* m_pSpeech;                     //语音播放类
	QMap<QString, QString> m_mapEngines;          //引擎列表
	QMap<QString, QLocale> m_mapLocales;          //加载语言
	QMap<QString, QVoice> m_mapVoice;             //加载语音  

	/*线程相关*/
	int m_nReConnectSplitNum;                     //重连次数
	int m_nReConnectSplitTime;                    //单次重连时间
	bool m_bIsInit;                               //是否初始化

	/*播报处理相关*/
	bool m_bSpeechPause;                          //暂停队列
	QQueue<QString> m_queueSpeech;                //播报队列 key为播报配置的id
	QEventLoop m_qSpeechLoop;                     //播报事件循环
	QMap<QString, SSpeechSet> m_mapSpeechData;    //队列中的播报数据
	bool m_bIsSpeak;                              //是否正在播报

	/*播报时间限制相关*/
	int m_nTimeSplit;							  //定时器时间间隔(ms)
	int m_nTimerType;                             //定时器请求类型
	QElapsedTimer m_qSpeechTime;                  //播报计时
	int m_nCurrLimitTime;                         //当前时间限制

	/*文件记录模块*/
	bool m_bOpenFileRecord;                       //打开文件记录
};

#endif